package com.sulent.frame.file.common.template;

import com.sulent.frame.file.common.properties.MinioConfigProperties;
import com.sulent.frame.file.utils.SubMinioClient;
import com.sulent.frame.support.exception.BusinessException;
import com.sulent.frame.support.utils.StringUtils;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.ListMultipartUploadsResult;
import io.minio.messages.Part;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName MinioTemplate
 * @Description: TODO
 * @Author Submerge.
 * @Since 2024/2/5 9:47
 * @Version 1.0
 */
@Component
public class MinioTemplate {


    @Autowired
    private MinioClient minioClient;

    @Autowired
    private SubMinioClient subMinioClient;

    @Autowired
    private MinioConfigProperties configProperties;

    public String putObject(String bucketName,String objectName,InputStream inputStream) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build();
            ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs);
            return objectWriteResponse.object();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return objectName;
    }

    public String statObject(String bucketName,String objectName) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        try {
            StatObjectArgs statObjectArgs = StatObjectArgs.builder().bucket(bucketName).object(objectName).build();
            StatObjectResponse statObjectResponse = minioClient.statObject(statObjectArgs);
            return statObjectResponse.etag();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(objectName+"对象不存在！");
        }
    }

    public File downloadObject(String bucketName, String objectName) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        File file = new File(objectName);
        if (file.exists()){
            file.delete();
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            DownloadObjectArgs build = DownloadObjectArgs.builder().bucket(bucketName).object(objectName).filename(objectName).overwrite(true).build();
            minioClient.downloadObject(build);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }

    public String getPreSignedObjectUrl(String bucketName, String objectName){
        String preSignedObjectUrl = null;
        GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).method(Method.GET).
                expiry(2, TimeUnit.HOURS).build();
        try {
            preSignedObjectUrl = minioClient.getPresignedObjectUrl(build);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return preSignedObjectUrl;
    }


    public void subPutObject(String bucketName,String objectName,InputStream inputStream) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build();
            subMinioClient.putObject(PutObjectArgs.builder().build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建分片任务
     *
     * @param bucketName
     * @param objectName
     * @return
     */
    public String createMultipartUpload(String bucketName, String objectName) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        CreateMultipartUploadResponse multipartUpload = null;
        try {
            multipartUpload = subMinioClient.createMultipartUpload(bucketName, null, objectName, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        assert multipartUpload != null;
        return multipartUpload.result().uploadId();
    }


    /**
     * 上传分片
     *
     * @param uploadId
     * @param partNumber
     * @param bucketName
     * @param objectName
     * @param inputStream
     * @return
     */
    public Part uploadPart(String uploadId, Integer partNumber, String bucketName, String objectName, InputStream inputStream) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        UploadPartResponse uploadPartResponse = null;
        try {
            uploadPartResponse = subMinioClient.uploadPart(bucketName, null, objectName, inputStream, inputStream.available(), uploadId, partNumber, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        assert uploadPartResponse != null;
        return new Part(partNumber, uploadPartResponse.etag());
    }


    /**
     * 合并分片
     *
     * @param uploadId
     * @param parts
     * @param bucketName
     * @param objectName
     */
    public void completeMultipartUpload(String uploadId, Part[] parts, String bucketName, String objectName) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }

        ObjectWriteResponse objectWriteResponse = null;
        try {
            objectWriteResponse = subMinioClient.completeMultipartUpload(bucketName, null, objectName, uploadId, parts, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 中止分段上传
     * @param uploadId
     * @param bucketName
     * @param objectName
     */
    public void abortMultipartUpload(String uploadId, String bucketName, String objectName) {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        AbortMultipartUploadResponse abortMultipartUploadResponse = null;
        try {
            abortMultipartUploadResponse = subMinioClient.abortMultipartUpload(bucketName, null, objectName, uploadId, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 列出已上传分片，上传结束后查不到
     * @param uploadId
     * @param maxParts
     * @param bucketName
     * @param objectName
     * @return
     */
    public List<Part> listParts(String uploadId, Integer maxParts, String bucketName, String objectName){
        if (StringUtils.isBlank(bucketName)) {
            bucketName = configProperties.getBucketName();
        }
        List<Part> parts = null;
        try {
            ListPartsResponse listPartsResponse = subMinioClient.listParts(bucketName, null, objectName, maxParts, 0, uploadId, null, null);
            parts = listPartsResponse.result().partList();
        }catch (Exception e){
            e.printStackTrace();
        }
        return parts;
    }

    /**
     * 列出桶中正在进行分片上传的任务
     *
     * @param bucketName
     * @return
     */
    public ListMultipartUploadsResult listMultiUpload(String bucketName){
        try {
            ListMultipartUploadsResponse listMultipartUploadsResponse = subMinioClient.listMultipartUploads(bucketName, null, null, null, null, null, null, null, null, null);
            return listMultipartUploadsResponse.result();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
